// PointSetWorkshop.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <cmath> 
#include <string>
#include <ctime>

#include "BinQuery.h"
#include "BinaryMinHeap.h"

using namespace std;

double next_double()
{
	return (double)rand() / RAND_MAX;
}

bool existInList(vector<void*>* set, void* key)
{
	for (auto p : *set)
	{
		if (p == key)
			return true;
	}
	return false;
}

int _tmain(int argc, _TCHAR* argv[])
{
	unsigned int dim = 3;
	double* coord_min = new double[dim]{-10.00001, -10.00001, -10.000001};
	double* coord_max = new double[dim]{10.000001, 10.00001, 10.00001};


	bool test_point_set = true;
	if (test_point_set)
	{
		unsigned int division_depth = 6;
		unsigned int* division = new unsigned int[6]{10, 10, 10, 10, 10, 10};

		vector<double*> samples;
		PointSet* ps = new BinQuery(dim, coord_max, coord_min, division_depth, division);
		cout << "Total bins = " << ((BinQuery*)ps)->n_bins << endl;

		int n_insert = 1000000;
		cout << endl << "Begin to insert " << n_insert << " points...";
		for (int i = 0; i < n_insert; ++i)
		{
			double* p = new double[3];
			p[0] = next_double() * 20 - 10;
			p[1] = next_double() * 20 - 10;
			p[2] = next_double() * 20 - 10;
			samples.push_back(p);
			ps->add_point(p, p);
		}
		cout << "   Done" << endl;

		int n_range_queries = 50000;
		cout << endl << "Begin range queries " << n_range_queries << " times...";
		clock_t t = clock();
		double range = 0.5;
		vector<double*>* results_coord = NULL;
		vector<void*>* results_object = NULL;
		for (int i = 0; i < n_range_queries; ++i)
		{
			double* p = new double[3];
			p[0] = next_double() * 20 - 10;
			p[1] = next_double() * 20 - 10;
			p[2] = next_double() * 20 - 10;

			ps->nearest_neighbor(p, range, results_coord, results_object);
		}
		t = clock() - t;
		cout << "   Done" << endl << "   time = " << (float)t / CLOCKS_PER_SEC << " seconds" << endl;

		cout << endl;
		cout << "Begin near neighbor result validation...";

		int n_validation_tests = 500;
		int n_successful = 0;
		for (int t_i = 0; t_i < n_validation_tests; ++t_i)
		{

			double* p = new double[3];
			p[0] = next_double() * 20 - 10;
			p[1] = next_double() * 20 - 10;
			p[2] = next_double() * 20 - 10;


			ps->nearest_neighbor(p, range, results_coord, results_object);

			int n_results_truth = 0;
			for (int i = 0; i < samples.size(); ++i)
			{
				double* p_i = samples[i];
				double distance2 = PointSet::Euclidean2(3, p_i, p);
				if (distance2 <= range * range)
				{
					if (existInList(results_object, p_i) == false)
					{
						cout << endl << "**************  Failed in range query validation *************" << endl << endl;
					}
					n_results_truth++;
				}
			}
			if (n_results_truth != results_object->size())
			{
				cout << endl << "**************  Failed in range query validation size *************" << endl << endl;
			}
			else
			{
				n_successful++;
			}
		}
		cout << "   Done" << endl << "   Success / Total = " << n_successful << " / " << n_validation_tests << endl;

		delete ps;
		cout << endl << "end of pointSet test " << endl << endl;
	}

	bool test_binary_heap = false;
	if (test_binary_heap)
	{
		BinaryMinHeap* heap = new BinaryMinHeap();

		int n_number = 100;
		for (int i = 0; i < n_number; ++i)
		{
			string s1("this is element(");
			string s2(")");
			string *s = new string(s1 + to_string(i) + s2);
			heap->push(-i, s);
		}


		while (heap->size()>0)
		{
			void* s;
			double k;
			heap->pop(k, s);

			cout << k << " :  " << (*(string*)s) << endl;
		}

	}






	cout << endl << endl << "press any key to continue ..." << endl;
	char tmp;
	cin >> tmp;

	return 0;
}

